Instruction on functional c
code: functional-c.mdc
### 🎯 Guidelines for Writing *Functional-Style* C Code
*(Each rule is immediately followed by a complete, compilable example.)*
---
#### 1. Favor a *functional* mind-set
**Rule 1** — Write *pure* functions whose result depends **only** on their inputs.
`c
// Pure: computes without reading globals or mutating state
int square(const int x)
{
return x * x;
}
`
---
#### 2. Mark **every** variable const
`c
int sumThree(const int a, const int b, const int c)
{
const int total = a + b + c;
return total;
}
`
---
#### 3. No mutation — one name ↔ one value
`c
const int initialCounter = 0;
const int nextCounter = initialCounter + 1;
`
---
#### 4. All dependencies come through arguments
`c
typedef struct
{
const size_t length;
const int *data;
} ConstIntArray;
double average(const ConstIntArray numbers)
{
const int sum = sumThree(numbers.data0, return (double)sum / (double)numbers.length;
}
`
---
#### 5. No side-effects (except wrapped syscalls)
`c
typedef struct
{
const bool succeeded;
const int result;
} ResultInt;
`
---
#### 6. Always wrap syscalls
`c
typedef struct { const bool succeeded; const int result; } ResultFd;
ResultFd openFileReadOnly(const char *const path)
{
const int fd = open(path, O_RDONLY);
return (ResultFd){
.succeeded = (fd != -1),
.result = (fd != -1) ? fd : -errno
};
}
`
---
#### 7. Canonical function skeleton
`c
int someFunction(const size_t a, const SomeType b)
{
const int valueA = otherFunction(a);
const size_t valueB = otherFunction(b);
return (valueA > THRESHOLD) ? valueB : EDGE_CASE;
}
`
---
#### 8. Consistent naming style
| Entity | Style | Example |
|-------------------------------|------------|------------|
| Functions / variables | camelCase | readFile |
| Types & typedef’d structs | PascalCase | ResultFd |
---
#### 9. **Avoid early returns — use a single, explicit control-flow block**
**Rule 9** — Instead of returning at multiple exit points, structure logic with a single if / else if / else ladder that ends in one return.
`c
int classifyScore(const int score)
{
int category = 0; // one mutable local allowed
// solely for the final return
if (score >= 90)
{
/* normal (excellent) case */
category = 1;
}
else if (score >= 75)
{
/* other normal case */
category = 2;
}
else
{
/* abnormal (error or low-score) case */
category = -1;
}
return category; // single exit point
}
`
*Notes*
* Only **one** return (the very last statement).
* The else if … else ladder makes every path explicit and keeps control-flow linear, which is easier to reason about in a functional style.
* The one mutable local (category) is an *exception* to Rule 3, justified because it represents the function’s eventual return value without causing observable side-effects.
---
## 10 · Predicate-Function Naming
Boolean-returning functions should read like **questions**—start them with
is, has, can, will, etc.—rather than a vague verb such as check.
`c
// âś… Good: name reads like a true/false question
bool isSizeOverflowed(const size_t size)
{
return size > MAX_ALLOWED_SIZE;
}
// ❌ Bad: generic “check” gives no hint that the result is Boolean
// bool checkSizeOverflow(const size_t size) { … }
`
**Why?**
Descriptive predicates make call sites self-documenting:
if (isSizeOverflowed(n)) is clearer than if (checkSizeOverflow(n)).
---
### 📌 Checklist
1. **Pure** functions, deterministic output.
2. const **everywhere** (rare, scoped exceptions allowed).
3. **Never** re-assign an existing identifier (Rule 3).
4. Pass **all** data via parameters.
5. Wrap **all** side-effects in Result… structs.
6. Follow the **function skeleton** format.
7. camelCase for functions/variables, **PascalCase** for types.
8. **Single exit point**: express flow with if / else if / else, no early returns.
9. * Use **predicate names** (is…, has…, can…, …) for all bool functions.
code: instruction.txt
### 🎯 Guidelines for Writing *Functional‑Style* C Code
*(Each rule is immediately followed by a complete, compilable example.)*
---
#### 1. Favor a *functional* mind‑set
**Rule 1** — Write *pure* functions whose result depends **only** on their inputs.
`c
// Pure: computes without reading globals or mutating state
int square(const int x)
{
return x * x;
}
`
---
#### 2. Mark **every** variable const
`c
int sumThree(const int a, const int b, const int c)
{
const int total = a + b + c;
return total;
}
`
---
#### 3. No mutation — one name ↔ one value
`c
const int initialCounter = 0;
const int nextCounter = initialCounter + 1;
`
---
#### 4. All dependencies come through arguments
`c
typedef struct
{
const size_t length;
const int *data;
} ConstIntArray;
double average(const ConstIntArray numbers)
{
const int sum = sumThree(numbers.data0, return (double)sum / (double)numbers.length;
}
`
---
#### 5. No side‑effects (except wrapped syscalls)
`c
typedef struct
{
const bool succeeded;
const int result;
} ResultInt;
`
---
#### 6. Always wrap syscalls
`c
typedef struct { const bool succeeded; const int result; } ResultFd;
ResultFd openFileReadOnly(const char *const path)
{
const int fd = open(path, O_RDONLY);
return (ResultFd){
.succeeded = (fd != -1),
.result = (fd != -1) ? fd : -errno
};
}
`
---
#### 7. Canonical function skeleton
`c
int someFunction(const size_t a, const SomeType b)
{
const int valueA = otherFunction(a);
const size_t valueB = otherFunction(b);
return (valueA > THRESHOLD) ? valueB : EDGE_CASE;
}
`
---
#### 8. Consistent naming style
| Entity | Style | Example |
|-------------------------------|------------|------------|
| Functions / variables | camelCase | readFile |
| Types & typedef’d structs | PascalCase | ResultFd |
---
#### 9. **Avoid early returns — use a single, explicit control‑flow block**
**Rule 9** — Instead of returning at multiple exit points, structure logic with a single if / else if / else ladder that ends in one return.
`c
int classifyScore(const int score)
{
int category = 0; // one mutable local allowed
// solely for the final return
if (score >= 90)
{
/* normal (excellent) case */
category = 1;
}
else if (score >= 75)
{
/* other normal case */
category = 2;
}
else
{
/* abnormal (error or low‑score) case */
category = -1;
}
return category; // single exit point
}
`
*Notes*
* Only **one** return (the very last statement).
* The else if … else ladder makes every path explicit and keeps control‑flow linear, which is easier to reason about in a functional style.
* The one mutable local (category) is an *exception* to Rule 3, justified because it represents the function’s eventual return value without causing observable side‑effects.
---
## 10 · Predicate‑Function Naming
Boolean‑returning functions should read like **questions**—start them with
is, has, can, will, etc.—rather than a vague verb such as check.
`c
// âś… Good: name reads like a true/false question
bool isSizeOverflowed(const size_t size)
{
return size > MAX_ALLOWED_SIZE;
}
// ❌ Bad: generic “check” gives no hint that the result is Boolean
// bool checkSizeOverflow(const size_t size) { … }
`
**Why?**
Descriptive predicates make call sites self‑documenting:
if (isSizeOverflowed(n)) is clearer than if (checkSizeOverflow(n)).
---
### 📌 Checklist
1. **Pure** functions, deterministic output.
2. const **everywhere** (rare, scoped exceptions allowed).
3. **Never** re‑assign an existing identifier (Rule 3).
4. Pass **all** data via parameters.
5. Wrap **all** side‑effects in Result… structs.
6. Follow the **function skeleton** format.
7. camelCase for functions/variables, **PascalCase** for types.
8. **Single exit point**: express flow with if / else if / else, no early returns.
9. * Use **predicate names** (is…, has…, can…, …) for all bool functions.
Stick to these rules and your C code will read—and behave—much like a functional language while keeping C’s power and performance.
Of course these rules apply for refactoring.
If you don't follow this rule, I'll kill you.